{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 利用聚类方法，根据企业的文本描述对企业进行分类 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## KMeans聚类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1、训练数据集：training.csv \n",
    "每个训练样本包含两个字段，分别为企业类别标签（1～10）和企业的文字描述（文本）。\n",
    "\n",
    "训练数据示例： \n",
    "1. 公司的主营业务为向中小微企业、个体工商户、农户等客户提供贷款服务，自设立以来主营业务未发生过变化。 \n",
    "2. 公司立足于商业地产服务，致力于为商业地产开发、销售、运营全产业链提供一整套增值服务，业务覆盖商业定位及策划、商业设计、销售代理、招商代理电子商务、以及商业地产运管服务；同时开展应用互联网电商模式，采取O2O线上导流线下服务方式进行住宅类业务的创新营销服务。公司的业务板块包括商业地产策划顾问、专业招商及运营管理、代理销售、麦吉铺O2O电子商务。 \n",
    "\n",
    "2、停用词字典：stopwords.txt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "批改标准\n",
    "1. 分词（20分）：由于企业描述是文本信息，需要对文本信息进行特征提取。文本分词可采用Jieba分词： \n",
    "https://github.com/fxsjy/jieba \n",
    "http://blog.csdn.net/FontThrone/article/details/72782499 \n",
    "2. 特征提取（20分）： 去掉停用词后（stopwords.txt），采用TFIDF作为每个文本的特征描述。 \n",
    "3. 采用KMeans聚类算法，根据第2 步得到特征对企业进行聚类， 尝试K=5，10，15，20，30，..., 50, 并选择合适的度量指标，选择最佳的K。（60分）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#导入必要的工具包\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "from sklearn.preprocessing import normalize\n",
    "from sklearn.cluster import MiniBatchKMeans\n",
    "\n",
    "from sklearn import metrics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 读取数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>idx</th>\n",
       "      <th>desc1</th>\n",
       "      <th>desc2</th>\n",
       "      <th>desc3</th>\n",
       "      <th>desc4</th>\n",
       "      <th>desc5</th>\n",
       "      <th>desc6</th>\n",
       "      <th>desc7</th>\n",
       "      <th>desc8</th>\n",
       "      <th>desc9</th>\n",
       "      <th>desc10</th>\n",
       "      <th>desc11</th>\n",
       "      <th>desc12</th>\n",
       "      <th>desc13</th>\n",
       "      <th>desc14</th>\n",
       "      <th>desc15</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.201257</td>\n",
       "      <td>0.213397</td>\n",
       "      <td>0.345230</td>\n",
       "      <td>0.295132</td>\n",
       "      <td>0.268914</td>\n",
       "      <td>0.353680</td>\n",
       "      <td>0.136433</td>\n",
       "      <td>0.131745</td>\n",
       "      <td>0.250276</td>\n",
       "      <td>0.186090</td>\n",
       "      <td>0.191881</td>\n",
       "      <td>0.122626</td>\n",
       "      <td>0.143040</td>\n",
       "      <td>0.233628</td>\n",
       "      <td>0.342308</td>\n",
       "      <td>0.005205</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.412775</td>\n",
       "      <td>0.387790</td>\n",
       "      <td>0.195999</td>\n",
       "      <td>0.145204</td>\n",
       "      <td>0.107634</td>\n",
       "      <td>0.062610</td>\n",
       "      <td>0.380532</td>\n",
       "      <td>0.156740</td>\n",
       "      <td>0.165767</td>\n",
       "      <td>0.129773</td>\n",
       "      <td>0.430503</td>\n",
       "      <td>0.108761</td>\n",
       "      <td>0.099341</td>\n",
       "      <td>0.192168</td>\n",
       "      <td>0.382858</td>\n",
       "      <td>0.005205</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.230312</td>\n",
       "      <td>0.135692</td>\n",
       "      <td>0.132694</td>\n",
       "      <td>0.128380</td>\n",
       "      <td>0.176043</td>\n",
       "      <td>0.194635</td>\n",
       "      <td>0.225698</td>\n",
       "      <td>0.172636</td>\n",
       "      <td>0.130001</td>\n",
       "      <td>0.188000</td>\n",
       "      <td>0.188000</td>\n",
       "      <td>0.168376</td>\n",
       "      <td>0.289694</td>\n",
       "      <td>0.188299</td>\n",
       "      <td>0.554742</td>\n",
       "      <td>0.002602</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.171969</td>\n",
       "      <td>0.158681</td>\n",
       "      <td>0.167908</td>\n",
       "      <td>0.203558</td>\n",
       "      <td>0.160436</td>\n",
       "      <td>0.424530</td>\n",
       "      <td>0.179712</td>\n",
       "      <td>0.163257</td>\n",
       "      <td>0.158681</td>\n",
       "      <td>0.155117</td>\n",
       "      <td>0.211965</td>\n",
       "      <td>0.156248</td>\n",
       "      <td>0.196564</td>\n",
       "      <td>0.399685</td>\n",
       "      <td>0.177678</td>\n",
       "      <td>0.005205</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.150162</td>\n",
       "      <td>0.115985</td>\n",
       "      <td>0.121602</td>\n",
       "      <td>0.130113</td>\n",
       "      <td>0.121602</td>\n",
       "      <td>0.195972</td>\n",
       "      <td>0.150881</td>\n",
       "      <td>0.625483</td>\n",
       "      <td>0.231970</td>\n",
       "      <td>0.121602</td>\n",
       "      <td>0.123583</td>\n",
       "      <td>0.121602</td>\n",
       "      <td>0.183911</td>\n",
       "      <td>0.324087</td>\n",
       "      <td>0.115985</td>\n",
       "      <td>0.005205</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        idx     desc1     desc2     desc3     desc4     desc5     desc6  \\\n",
       "0  0.201257  0.213397  0.345230  0.295132  0.268914  0.353680  0.136433   \n",
       "1  0.412775  0.387790  0.195999  0.145204  0.107634  0.062610  0.380532   \n",
       "2  0.230312  0.135692  0.132694  0.128380  0.176043  0.194635  0.225698   \n",
       "3  0.171969  0.158681  0.167908  0.203558  0.160436  0.424530  0.179712   \n",
       "4  0.150162  0.115985  0.121602  0.130113  0.121602  0.195972  0.150881   \n",
       "\n",
       "      desc7     desc8     desc9    desc10    desc11    desc12    desc13  \\\n",
       "0  0.131745  0.250276  0.186090  0.191881  0.122626  0.143040  0.233628   \n",
       "1  0.156740  0.165767  0.129773  0.430503  0.108761  0.099341  0.192168   \n",
       "2  0.172636  0.130001  0.188000  0.188000  0.168376  0.289694  0.188299   \n",
       "3  0.163257  0.158681  0.155117  0.211965  0.156248  0.196564  0.399685   \n",
       "4  0.625483  0.231970  0.121602  0.123583  0.121602  0.183911  0.324087   \n",
       "\n",
       "     desc14    desc15  \n",
       "0  0.342308  0.005205  \n",
       "1  0.382858  0.005205  \n",
       "2  0.554742  0.002602  \n",
       "3  0.177678  0.005205  \n",
       "4  0.115985  0.005205  "
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#读取训练数据\n",
    "#dpath = './data/'\n",
    "train = pd.read_csv(\"train_tfidf.csv\",header=None,names=['idx','desc1','desc2','desc3','desc4','desc5','desc6'\n",
    "                                                     ,'desc7','desc8','desc9','desc10','desc11','desc12'\n",
    "                                                     ,'desc13','desc14','desc15'])\n",
    "train.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 准备数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.21613421,  0.22917137,  0.37074973, ...,  0.25089774,\n",
       "         0.36761197,  0.00558952],\n",
       "       [ 0.41276974,  0.38778471,  0.19599621, ...,  0.19216526,\n",
       "         0.38285243,  0.0052047 ],\n",
       "       [ 0.25778316,  0.15187693,  0.14852098, ...,  0.21075872,\n",
       "         0.6209091 ,  0.00291279],\n",
       "       ..., \n",
       "       [ 0.19949245,  0.23270292,  0.18357155, ...,  0.23270292,\n",
       "         0.23270292,  0.02034656],\n",
       "       [ 0.43582224,  0.11041461,  0.16905771, ...,  0.13432405,\n",
       "         0.17458667,  0.01405457],\n",
       "       [ 0.31072262,  0.18751397,  0.16203359, ...,  0.36786795,\n",
       "         0.56904651,  0.01015836]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train = train\n",
    "\n",
    "#数据进行归一：每个样本的模长为1\n",
    "normalize(X_train, norm=\"l2\", copy=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## KMeans聚类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 一个参数点（聚类数据为K）的模型\n",
    "def K_cluster_analysis(K, X):\n",
    "    print(\"K-means begin with clusters: {}\".format(K));\n",
    "    \n",
    "    #K-means,在训练集上训练\n",
    "    mb_kmeans = MiniBatchKMeans(n_clusters = K)\n",
    "    y_pred = mb_kmeans.fit_predict(X)\n",
    "    \n",
    "    # K值的评估标准\n",
    "    #本案例中训练数据有标签，可采用有参考模型的评价指标\n",
    "    #v_score = metrics.v_measure_score(y_val, y_val_pred)\n",
    "    \n",
    "    #亦可采用无参考默的评价指标：轮廓系数Silhouette Coefficient和Calinski-Harabasz Index\n",
    "    #这两个分数值越大则聚类效果越好\n",
    "    CH_score = metrics.calinski_harabaz_score(X, y_pred)\n",
    "    \n",
    "    #轮廓系数Silhouette Coefficient在大样本时计算太慢\n",
    "    #si_score = metrics.silhouette_score(X, y_pred)\n",
    "    \n",
    "    print(\"CH_score: {}\".format(CH_score))\n",
    "    #print(\"si_score: {}\".format(si_score))\n",
    "    \n",
    "    return CH_score#,si_score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "K-means begin with clusters: 5\n",
      "CH_score: 244.46707875807311\n",
      "K-means begin with clusters: 10\n",
      "CH_score: 261.857822965063\n",
      "K-means begin with clusters: 15\n",
      "CH_score: 283.3042387067448\n",
      "K-means begin with clusters: 20\n",
      "CH_score: 281.59023207858365\n",
      "K-means begin with clusters: 25\n",
      "CH_score: 238.61641222528874\n",
      "K-means begin with clusters: 30\n",
      "CH_score: 216.05060378373315\n",
      "K-means begin with clusters: 40\n",
      "CH_score: 174.0967969572924\n",
      "K-means begin with clusters: 50\n",
      "CH_score: 137.3347508900659\n",
      "K-means begin with clusters: 60\n",
      "CH_score: 122.73380226201196\n"
     ]
    }
   ],
   "source": [
    "# 设置超参数（聚类数目K）搜索范围\n",
    "Ks = [5,10,15,20,25,30,40,50,60]\n",
    "CH_scores = []\n",
    "#si_scores = []\n",
    "for K in Ks:\n",
    "    ch = K_cluster_analysis(K, X_train)\n",
    "    CH_scores.append(ch)\n",
    "    #si_scores.append(si)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "15\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXoAAAD8CAYAAAB5Pm/hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzt3Xl4VNX9x/H3F1CQRVEJiIAFFRfa\nnwIOFEVFQBTcUEFFraKiWIsK1i7ivre11rWtFgGVuiDKIlVEca9awICiItXiHkGJdYGWigLf3x/n\n5skYAxmSmdyZO5/X8+TJzJ078XvbPJ9czpzzPebuiIhIcjWIuwAREcktBb2ISMIp6EVEEk5BLyKS\ncAp6EZGEU9CLiCScgl5EJOEU9CIiCaegFxFJuEZxFwDQqlUr79ixY9xliIgUlAULFnzm7iU1nZcX\nQd+xY0dKS0vjLkNEpKCY2QeZnKehGxGRhFPQi4gknIJeRCThFPQiIgmnoBcRSTgFvYhIwinoRUQS\nLi/m0cv3ucOkSVBeDttuC61afff71ltDA/2ZFpEMKOjz0Pr1cNZZMG7chs9p0CCEfdU/ABv7vs02\n0LBh/V2HiOSHGoPezDoAk4DtgPXAOHe/2cy6ArcDTYC1wM/cfb6ZGXAzcAiwGjjF3Rfm6gKSZu1a\nOPVUuOceuPBCuOAC+Pe/4bPPwlfF46rfP/gAFiwIj9es2fDP39gfh912gyOPBLP6u14Ryb1M7ujX\nAue7+0IzawEsMLM5wHXAFe7+mJkdEj0/ABgEdI6+fgzcFn2XGqxZA8cfD9OnwzXXhKAHaNECMm0F\n5A6rV2f2x+Hjj2HRovB89erw/vvuCzWISHLUGPTuvhxYHj1eZWZLgHaAA1tGp20FLIseDwYmubsD\nc82spZm1jX6ObMD//gdHHw2zZ8NNN8Ho0bX7OWbQrFn42mGHzN+3ejXsvTdceikMHQqbbVa7/76I\n5J9N+jjPzDoC3YB5wBjg92b2EXA9MDY6rR3wUdrbyqJjVX/WSDMrNbPS8vLyTa88QVatgkGD4PHH\n4Y47ah/yddG0KVx9NSxdCnffXf//fRHJnYyD3syaA1OBMe6+EjgLOM/dOwDnARMqTq3m7f69A+7j\n3D3l7qmSkhq7bCbWF1/AgAHwwgtw771w+unx1XLYYdCrF1xxBXz9dXx1iEh2ZRT0ZrYZIeTvdfdp\n0eHhQMXjB4Ge0eMyoEPa29tTOawjaVasgL594ZVXYOrU+MfGzeDaa6GsDG6/Pd5aRCR7agz6aBbN\nBGCJu9+Q9tIyoE/0uB/wr+jxTOBkC3oBX2l8/vs+/hj69IG334aZM2Hw4LgrCvr2hQMPDIG/alXc\n1YhINmRyR98bOAnoZ2avRl+HAGcAfzCzRcC1wMjo/FnAu8BS4A7gZ9kvu7C9/z7sv3+4c549Gw4+\nOO6Kvuuaa8JCrZtvjrsSEckGC5Nj4pVKpbxYdph6661wx/zf/4aQ79mz5vfE4cgj4Zln4L33wkIr\nEck/ZrbA3VM1nadF9PXotdfCnfw338Czz+ZvyANcdVUYurnuurgrEZG6UtDXk5dfhgMOCPPTn3sO\n9tgj7oo27v/+D044AW65BZbrExaRgqagrwd//zv07w8tW4bHu+0Wd0WZufxy+Pbb8MGsiBQuBX2O\nzZkTPmzdfnt4/nno1CnuijK3884wYgT85S/hA2QRKUwK+hyaOTMsQurcOYR8+/ZxV7TpLrkkdMq8\n4oq4KxGR2lLQ58jkyaF3TdeuYfZK69ZxV1Q77drB2WeH3vhLlsRdjYjUhoI+ByZODB9k9u4NTz5Z\n+NMTL7gg9MK59NK4KxGR2lDQZ9mtt4Zx7YMOgsceCy2GC12rVvDzn8NDD4We9yJSWBT0WfSb38C5\n54bFRg8/HO6Ck+LnPw//Mrn44rgrEZFNpaDPAne46KKwUcgJJ8CUKdC4cdxVZddWW4UhnNmzwwfL\nIlI4FPR15A7nnRfmmp9+evjQMqmbdowaBW3bhj9qedA5Q0QypKCvg3XrYOTI0Pxr9OiwmXeSN99u\n2jRMt3zhhXBnLyKFQUFfS99+CyefDOPHhzvcG28sjk21R4wIi74uugjWr4+7GhHJhIK+FtasgWOP\nDRtpX3tt2IKvGEIeYPPNw+KpV16BadNqPl9E4qeg30SrV4dNQmbMCA2/xo6t+T1Jc8IJ0KVLGMZZ\nuzbuakSkJpnsMNXBzJ4xsyVmttjMRqe9do6ZvRUdvy7t+FgzWxq9lmfbatTeypVhE+8nnoAJE+Cc\nc+KuKB4NG4Z/xfzzn3DPPXFXIyI1aZTBOWuB8919oZm1ABaY2RygDTAY2MPd15hZawAz6wIMA34I\nbA88aWa7uPu63FxC/Vi6FIYMgcWLw5DNsGFxVxSvI4+EVCp0uDz++ORNJxVJkhrv6N19ubsvjB6v\nApYA7YCzgN+6+5rotRXRWwYDk919jbu/R9hSMI+32KjZjBmw115h679HH1XIQ/hM4ppr4IMP4I47\n4q5GRDZmk8bozawj0A2YB+wC7Gdm88zsOTPrEZ3WDvgo7W1l0bGCs3Yt/PrXcNRRsMsusHBh/u3v\nGqcBA8IG51dfHbZGFJH8lHHQm1lzYCowxt1XEoZ9tgZ6Ab8EppiZAdXNP/ne8hozG2lmpWZWWl5e\nXqvic+nTT0OQXXcdnHlm2DDkBz+Iu6r8UnFX/+mnocePiOSnjILezDYjhPy97l4xqa4MmObBfGA9\n0Co63iHt7e2BZVV/pruPc/eUu6dKSkrqcg1Z9+KL0K0bzJ0Ld90Ft98OTZrEXVV+6t0bDj0Ufvc7\n+PLLuKsRkepkMuvGgAnAEne/Ie2lGUC/6JxdgM2Bz4CZwDAza2xmnYDOwPxsF54L7nDTTWFv16ZN\nQ9APHx53Vfnv6qtDyF9/fdyViEh1Mrmj7w2cBPQzs1ejr0OAicCOZvYGMBkYHt3dLwamAG8Cs4FR\nhTDjZtWq8CHreeeFO9TSUthzz7irKgxdu8Jxx4U/kitW1Hy+iNQv8zzoTpVKpby0tDS2//6bb4ap\nk2+/HVoN//KXxbPSNVvefjssojrnnNAOQkRyz8wWuHuqpvOKfmXs5MnQsyd8/jk89RT86lcK+drY\nZRc45RT485/hww/jrkZE0hVt0H/zTeg4efzxYejhlVfC2LzUXsVWg1ddFW8dIvJdRRn0ZWUh1G+5\nBcaMCZt3b7993FUVvh12gJ/+FO68MwzliEh+KLqgf/pp6N4dXn8dHnggjCcndaOQOFx4YWiHcNll\ncVciIhWKJujXr4ff/jYsgmrVCubPD62GJbvatAn/Spo8GRYtirsaEYEiCfovvwxtDMaODeE+fz7s\nvnvcVSXXL34BLVtqI3GRfJH4oH/11dCQbNasMCZ/333QvHncVSXb1luH2UuPPAIvvRR3NSKS6KC/\n6y7Ye++wI9Tzz4c53po6WT/OPRdat9ZG4iL5IJFB//XXYdPuU0+FffYJXSf33jvuqopLs2Zh6ObZ\nZ8P6BBGJT+KC/r33QqOtO+4IM0CeeCLcWUr9GzkyTLm88ELd1YvEKVFBP2tWGI9/5x2YOTO00G3Y\nMO6qilfjxmEHqpdfhocfjrsakeKViKBfty6syjz00NAzfsECOPzwuKsSgJNOgl13DcM46/K+tZ1I\nMhV80H/2Wdiw+6qrwpj8Sy/BTjvFXZVUaNQIrrwy7LV7//1xVyNSnAo66EtLwyrX55+H8eNh4kTY\nYou4q5Kqhg4N/YQuuyz0GBKR+lXQQb9uXdgg5KWXYMSIuKuRDWnQIHxe8u674Y+xiNSvgu9Hv26d\nPnAtBO6w334h7N95R//yEsmGrPWjN7MOZvaMmS0xs8VmNrrK678wMzezVtFzM7NbzGypmb1mZt1r\nfxk1U8gXBjO49lpYvhz+9Ke4qxEpLpkM3awFznf33YFewCgz6wLhjwAwAEjfamIQYZ/YzsBI4Las\nViwFa//94eCDwy5eK1fGXY1I8agx6N19ubsvjB6vApYA7aKXbwR+BaSP/wwGJkX7x84FWppZ2+yW\nLYXqmmvCbl7ablCk/mzSh7Fm1hHoBswzsyOAj929ajPadsBHac/LqPzDIEVur73C/rx/+EOYGisi\nuZdx0JtZc2AqMIYwnHMRcGl1p1Zz7Huf+JrZSDMrNbPS8vLyTMuQBLjySvjPf8KYvYjkXkZBb2ab\nEUL+XnefBuwEdAIWmdn7QHtgoZltR7iD75D29vbAsqo/093HuXvK3VMlJSV1uwopKF26hOmwN94I\n48bFXY1I8jWq6QQzM2ACsMTdbwBw99eB1mnnvA+k3P0zM5sJnG1mk4EfA1+5+/JcFC+F649/DDNw\nzjwzPB85Mt56RJIskzv63sBJQD8zezX6OmQj588C3gWWAncAP6t7mZI0jRvD1KmhP9GZZ4ZuoyKS\nGzXe0bv7C1Q/7p5+Tse0xw6MqnNlkngVYX/00eGO3gxOPz3uqkSSp6BbIEjhqwj7QYPgjDNgwoS4\nKxJJHgW9xK5JE5g2DQYODGGvfjgi2aWgl7zQpAlMnx5Wzp5+Otx5Z9wViSSHgl7yRkXYH3RQmH55\n111xVySSDAp6yStNmsCMGTBgAJx2Gtx9d9wViRQ+Bb3knYqwP/DAsGuYwl6kbhT0kpe22CJsKN6/\nfwj7SZPirkikcCnoJW9VhH2/fnDKKfDXv8ZdkUhhUtBLXmvaFGbOhL59YfhwuOeeuCsSKTwKesl7\nTZvC3/5WGfb33ht3RSKFRUEvBaEi7Pv0gZNPhvvui7sikcKhoJeCURH2++8PJ52ksBfJlIJeCkqz\nZvDII5VhP3ly3BWJ5D8FvRScirDfbz848UR44IG4KxLJbwp6KUjNmsGjj8K++4awnzIl7opE8peC\nXgpWRdjvsw+ccAI8+GDcFYnkpxqD3sw6mNkzZrbEzBab2ejo+O/N7J9m9pqZTTezlmnvGWtmS83s\nLTM7OJcXIMWteXOYNSuE/fHHK+xFqpPJHf1a4Hx33x3oBYwysy7AHOBH7r4H8DYwFiB6bRjwQ2Ag\n8Gcza5iL4kWgMuz33juE/UMPxV2RSH6pMejdfbm7L4werwKWAO3c/Ql3XxudNhdoHz0eDEx29zXu\n/h5h79ie2S9dpFJF2PfqBcOGhV2rRCTYpDF6M+sIdAPmVXnpNOCx6HE74KO018qiY1V/1kgzKzWz\n0vLy8k0pQ6RaLVrAY4/Bj38cwn7atLgrEskPGQe9mTUHpgJj3H1l2vGLCMM7FQvTq9tI3L93wH2c\nu6fcPVVSUrJpVYtsQEXY9+gBxx0XNjIRKXYZBb2ZbUYI+XvdfVra8eHAYcCJ7l4R5mVAh7S3tweW\nZadckZptuSXMnh3C/thjFfYimcy6MWACsMTdb0g7PhD4NXCEu69Oe8tMYJiZNTazTkBnYH52yxbZ\nuIqwT6VC2M+YEXdFIvHJ5I6+N3AS0M/MXo2+DgH+CLQA5kTHbgdw98XAFOBNYDYwyt3X5aZ8kQ2r\nCPu99oJjjtGYvRQvqxxxiU8qlfLS0tK4y5CE+uorGDgQ5s+HCRPCJiYiSWBmC9w9VdN5WhkribfV\nVjBnTuW2hDffHHdFIvVLQS9FoXnz0OL46KNhzBi4/HLIg3/MitQLBb0UjcaNQ6fLU0+FK66A0aNh\n/fq4qxLJvUZxFyBSnxo1gvHjoWVLuPHGMH4/YUI4LpJU+vWWotOgAfzhD7DNNnDJJbByJdx/PzRp\nEndlIrmhoRspSmZw8cVw661hjv2hh8KqVXFXJZIbCnopamefDZMmwXPPwYEHwr//HXdFItmnoJei\nd9JJYTHVokXQpw8sU8MOSRgFvQhwxBGhGdoHH4TtCd95J+6KRLJHQS8S6dsXnn46zMTZd1944424\nKxLJDgW9SJoePeDvfw8zc/bfH+ZV3XlBpAAp6EWq6NIFXnghTL/s3x+efDLuikTqRkEvUo1OncKd\n/Y47hqmX6mkvhUxBL7IBbdvCs89C9+4wdCjcdVfcFYnUjoJeZCO22SYM3ajzpRSyTHaY6mBmz5jZ\nEjNbbGajo+PbmNkcM/tX9H3r6LiZ2S1mttTMXjOz7rm+CJFcatbsu50vL7tMnS+lsGRyR78WON/d\ndwd6AaPMrAtwAfCUu3cGnoqeAwwibB/YGRgJ3Jb1qkXqWXrnyyuvVOdLKSw1NjVz9+XA8ujxKjNb\nArQDBgMHRKfdDTxL2EN2MDAp2ix8rpm1NLO20c8RKVjqfCmFapN+Rc2sI9ANmAe0qQhvd19uZq2j\n09oBH6W9rSw6pqCXgle18+VXX8Hkyep8Kfkt4w9jzaw5MBUY4+4rN3ZqNce+N6JpZiPNrNTMSsvL\nyzMtQyR26Z0vH35YnS8l/2UU9Ga2GSHk73X3adHhT82sbfR6W2BFdLwM6JD29vbA99pEufs4d0+5\ne6qkpKS29YvE5uyz4a9/VedLyX+ZzLoxYAKwxN1vSHtpJjA8ejwceDjt+MnR7JtewFcan5ek+slP\n1PlS8l8md/S9gZOAfmb2avR1CPBbYICZ/QsYED0HmAW8CywF7gB+lv2yRfKHOl9KvjPPgwnBqVTK\nS0tL4y5DpE5efhkGDYLNNoM5c+BHP4q7Ikk6M1vg7qmaztPKWJEs6dEDnn++svPl3LlxVyQSKOhF\nsii98+WBB6rzpeQHBb1IlqnzpeQbBb1IDrRtG6Zd7rWXOl9K/BT0Ijmy9dbhQ9mKzpc33RR3RVKs\nFPQiOZTe+fK889T5UuKhoBfJMXW+lLip755IPWjUKHS63HpruOEGdb6U+qVfM5F6YgbXXx/CXp0v\npT5p6EakHqnzpcRBQS8Sg/TOl/37q/Ol5JaCXiQmFZ0vX3sttEz4+OO4K5KkUtCLxKii8+WHH8J+\n+6nzpeSGgl4kZn37wjPPwMqVoc3x66/HXZEkjYJeJA+kUpWdL/v0UedLyS4FvUie6NIFXnxRnS8l\n+zLZSnCima0wszfSjnU1s7nRblOlZtYzOm5mdouZLTWz18ysey6LF0majh1Dm+OKzpfTptX4FpEa\nZXJHfxcwsMqx64Ar3L0rcGn0HGAQ0Dn6Ggnclp0yRYrHdttVdr485hh1vpS6qzHo3f154POqh4Et\no8dbARVbIg8GJnkwF2hpZm2zVaxIsVDnS8mm2rZAGAM8bmbXE/5Y7BMdbwd8lHZeWXRsedUfYGYj\nCXf97LDDDrUsQyS5Kjpfnnhi6Hz5xRdw+eVhda3Ipqjth7FnAee5ewfgPGBCdLy6X8Fqm7K6+zh3\nT7l7qqSkpJZliCRb48ahH85pp6nzpdRebe/ohwOjo8cPAuOjx2VAh7Tz2lM5rCMitdCoEYwfDy1b\nhs6XX34JEyeq86VkrrZ39MuAPtHjfsC/osczgZOj2Te9gK/c/XvDNiKyaSo6X159deiRM3QofP11\n3FVJoajxnsDM7gcOAFqZWRlwGXAGcLOZNQK+JhprB2YBhwBLgdXAqTmoWaQomcFFF4U7+7PPhkMO\nCR0wW7SIuzLJdzUGvbsfv4GX9qrmXAdG1bUoEdmwUaNgq63glFPCrJzHHoNtt427KslnWhkrUoB+\n8hOYPl2dLyUzCnqRAnX44TB7duh8uc8+8OqrcVck+UpBL1LADjggrKJdtw5694YHH4y7IslHCnqR\nAte9O5SWwp57wrHHwqWXaq69fJeCXiQBttsu9LQ/9VS46ioYMkR70UolBb1IQjRuDBMmhL44M2eG\ncft33427KskHCnqRBDELbRJmzw4zcXr0CHf6UtwU9CIJNGAAzJ8PbdqEx3/6E3i1XaekGCjoRRJq\n553DloSDBoWVtGeeCd98E3dVEgcFvUiCbbklzJgBY8fCHXeElbQrVsRdldQ3Bb1IwjVsCNdeC/ff\nDwsWhHF7La4qLgp6kSIxbFjYj3b9+jAjR4urioeCXqSIVCyu6tYtLK665BItrioGCnqRItOmDTz9\nNIwYEfrbH320FlclnYJepAg1bhw+nL3lFnjkEdh7by2uSrIag97MJprZCjN7o8rxc8zsLTNbbGbX\npR0fa2ZLo9cOzkXRIlJ3ZnDOOfD447BsWfiQ9umn465KciGTO/q7gIHpB8ysLzAY2MPdfwhcHx3v\nAgwDfhi9589m1jCbBYtIdvXvDy+/HPrlHHQQ/PGPWlyVNDUGvbs/D3xe5fBZwG/dfU10TsXM3MHA\nZHdf4+7vEbYU7JnFekUkB3baCf7xj7A94TnnwMiRWlyVJLUdo98F2M/M5pnZc2bWIzreDvgo7byy\n6JiI5LmKxVUXXQTjx2txVZLUNugbAVsDvYBfAlPMzACr5txq/xFoZiPNrNTMSsvLy2tZhohkU4MG\nYSbO5MlhcVUqBa+8EndVUle1DfoyYJoH84H1QKvoeIe089oDy6r7Ae4+zt1T7p4qKSmpZRkikgvH\nHRcWV0HYuWrKlHjrkbqpbdDPAPoBmNkuwObAZ8BMYJiZNTazTkBnYH42ChWR+tW9e/iQtnv3EPwX\nX6zFVYUqk+mV9wP/AHY1szIzGwFMBHaMplxOBoZHd/eLgSnAm8BsYJS7r8td+SKSS23awFNPhcVV\n11yjxVWFyjwP5lGlUikvLS2NuwwR2QD3MO3yvPNgt93g4YfDTB2Jl5ktcPdUTedpZayI1Ch9cdXy\n5dCzZ7jTl8KgoBeRjPXvH3auatsWDj4Ybr1Vi6sKgYJeRDZJxeKqQw+Fc8/V4qpCoKAXkU3WogVM\nnx5m4owfD/36waefxl2VbIiCXkRqpUEDuOoqeOABWLgwNEVbuDDuqqQ6CnoRqZNjj4UXXwyP9903\nBL/kFwW9iNRZt26Vi6uGDdPiqnyjoBeRrKjYuer008PiqqOOgpUr465KQEEvIlm0+eYwblyYdvno\no2HnqnfeibsqUdCLSFaZwdlnwxNPwCefhA9pn3wy7qqKm4JeRHKiX78wbr/99jBwYNifVour4qGg\nF5Gc2XHHsLjqsMNg9Ogwfr9mTdxVFR8FvYjkVIsWMG1amIkzcWK40//kk7irKi4KehHJuYrFVVOm\nhB2revQIO1hJ/VDQi0i9OeaYsLjKLCyumjw57oqKg4JeROpVt25QWhr2oz3+eLjwQi2uyrVMdpia\naGYrot2kqr72CzNzM2sVPTczu8XMlprZa2bWPRdFi0hha9069LM/4wz4zW9g8GAtrsqlTO7o7wIG\nVj1oZh2AAcCHaYcHEfaJ7QyMBG6re4kikkSbbw5/+UvYueqxx6BXL1i6NO6qkqnGoHf354HPq3np\nRuBXQPrM2MHApGj/2LlASzNrm5VKRSRxzGDUKJgzB1asCDtXaXFV9tVqjN7MjgA+dvdFVV5qB3yU\n9rwsOiYiskF9+4bFVe3ahZ2rbr5Zi6uyaZOD3syaAhcBl1b3cjXHqv2/y8xGmlmpmZWWl5dvahki\nkjCdOsFLL8ERR8CYMTBihBZXZUtt7uh3AjoBi8zsfaA9sNDMtiPcwXdIO7c9sKy6H+Lu49w95e6p\nkpKSWpQhIknTogVMnQqXXgp33hnu9LW4qu42Oejd/XV3b+3uHd29IyHcu7v7J8BM4ORo9k0v4Ct3\nX57dkkUkyRo0gCuugAcfhEWLQo/7yy6D117TcE5tZTK98n7gH8CuZlZmZiM2cvos4F1gKXAH8LOs\nVCkiRWfo0LC4atdd4eqrYc89YZdd4IILwni+Qj9z5nnwv1YqlfLS0tK4yxCRPPXpp/Dww/DQQ/DM\nM7B2LfzgB3D00TBkSOh736AIl3+a2QJ3T9V4noJeRArJ55/DzJlhLP+JJ+Cbb6Bt27Cj1ZAhsP/+\n0KhR3FXWDwW9iCTeypVhJ6upU2HWLPjf/6BVq7DSdujQ0Clz883jrjJ3FPQiUlT++1+YPTuE/iOP\nwKpVsNVWYbrmkCFw0EGwxRZxV5ldCnoRKVpffx1W2E6dGsb2v/gCmjWDQw8NoX/IIdC8edxV1p2C\nXkQE+Pbb8AHu1KkwfTqUl0OTJmF7wyFD4PDDw51/IVLQi4hUsW4dvPBCCP2pU2HZMthsMzjwwBD6\ngweHMf5CoaAXEdmI9eth3rzK0H//fWjYEPr0CR/kHnUUbLdd3FVunIJeRCRD7mGLw6lTw1z9t98O\nnTV79w53+kcfDTvsEHeV36egFxGpBXdYvLjyTv/118PxHj1C6A8ZAjvvHG+NFRT0IiJZ8PbbMG1a\nCP2KmNpzz8rQ79IlvtoU9CIiWfb++5Wh/9JL4dhuu1WGfteuYcinvijoRURyaNmyMF1z6lR47rnw\n4e6OO1aGfs+euQ99Bb2ISD0pL4cZM0LoP/VUaLrWvn1l07XevcOMnmxT0IuIxOCLL+Bvfwuh//jj\nYZesNm0qm6716RPm7meDgl5EJGarVn236drq1bDNNmFh1pAhYaFW48a1//mZBn0RdnAWEakfLVrA\nsGFht6zy8vBB7qBBIfgPOwxat4Ybbsh9HZnsMDXRzFaY2Rtpx35vZv80s9fMbLqZtUx7bayZLTWz\nt8zs4FwVLiJSSJo2DcM399wDK1aEDptDhoSx/FyrcejGzPYH/gNMcvcfRccOAp5297Vm9jsAd/+1\nmXUB7gd6AtsDTwK7uPu6jf03NHQjIrLpsjZ04+7PA59XOfaEu6+Nns4FKv4mDQYmu/sad3+PsHds\nz02qXEREsiobY/SnAY9Fj9sBH6W9VhYd+x4zG2lmpWZWWl5enoUyRESkOnUKejO7CFgL3FtxqJrT\nqh0bcvdx7p5y91RJSUldyhARkY2o9Ra6ZjYcOAzo75UD/WVAh7TT2gPLal+eiIjUVa3u6M1sIPBr\n4Ah3X5320kxgmJk1NrNOQGdgft3LFBGR2qrxjt7M7gcOAFqZWRlwGTAWaAzMsdDMYa67/9TdF5vZ\nFOBNwpDOqJpm3IiISG5pZayISIHSylgREQHy5I7ezMqBD+KuI0OtgM/iLiJHknxtkOzr07UVrrpc\n3w/cvcZpi3kR9IXEzEoz+adSIUrytUGyr0/XVrjq4/o0dCMiknAKehGRhFPQb7pxcReQQ0m+Nkj2\n9enaClfOr09j9CIiCac7ehGRhFPQb8QGNl3ZxszmmNm/ou9bx1ljbZlZBzN7xsyWmNliMxsdHS/4\n6zOzJmY238wWRdd2RXS8k5nNi67tATPbPO5aa8vMGprZK2b2SPQ8Sdf2vpm9bmavmllpdKzgfy8B\nzKylmT0Ubdy0xMz2ro9rU9CvuZI5AAACyElEQVRv3F3AwCrHLgCecvfOwFPR80K0Fjjf3XcHegGj\noo1jknB9a4B+7r4n0BUYaGa9gN8BN0bX9gUwIsYa62o0sCTteZKuDaCvu3dNm3aYhN9LgJuB2e6+\nG7An4f/D3F+bu+trI19AR+CNtOdvAW2jx22Bt+KuMUvX+TAwIGnXBzQFFgI/JixKaRQd3xt4PO76\nanlN7aNA6Ac8QmgPnohri+p/H2hV5VjB/14CWwLvEX02Wp/Xpjv6TdfG3ZcDRN9bx1xPnZlZR6Ab\nMI+EXF80tPEqsAKYA7wDfOmVO6NtcFOcAnAT8CtgffR8W5JzbRD2sHjCzBaY2cjoWBJ+L3cEyoE7\no2G38WbWjHq4NgV9kTOz5sBUYIy7r4y7nmxx93Xu3pVw99sT2L260+q3qrozs8OAFe6+IP1wNacW\n3LWl6e3u3YFBhCHF/eMuKEsaAd2B29y9G/Bf6mkISkG/6T41s7YA0fcVMddTa2a2GSHk73X3adHh\nxFwfgLt/CTxL+ByipZlVtOYu1E1xegNHmNn7wGTC8M1NJOPaAHD3ZdH3FcB0wh/qJPxelgFl7j4v\nev4QIfhzfm0K+k03ExgePR5OGNsuOBY2EpgALHH3G9JeKvjrM7MSM2sZPd4COJDwodczwNDotIK8\nNncf6+7t3b0jMAx42t1PJAHXBmBmzcysRcVj4CDgDRLwe+nunwAfmdmu0aH+hL07cn5tWjC1Eemb\nrgCfEjZdmQFMAXYAPgSOcffP46qxtsxsX+DvwOtUjvVeSBinL+jrM7M9gLuBhoSbmSnufqWZ7Ui4\nC94GeAX4ibuvia/SujGzA4BfuPthSbm26DqmR08bAfe5+zVmti0F/nsJYGZdgfHA5sC7wKlEv6Pk\n8NoU9CIiCaehGxGRhFPQi4gknIJeRCThFPQiIgmnoBcRSTgFvYhIwinoRUQSTkEvIpJw/w8+h5sl\n/wFY7wAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0xdecdc18>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 绘制不同K对应的聚类的性能，找到最佳模型／参数（分数最高）\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "plt.plot(Ks, np.array(CH_scores), 'b-',label = 'CH_scores')\n",
    "\n",
    "\n",
    "### 最佳超参数\n",
    "index = np.unravel_index(np.argmax(CH_scores, axis=None), len(CH_scores))\n",
    "Best_K = Ks[ index[0]]\n",
    "\n",
    "print(Best_K)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 用最佳的K再次聚类，得到聚类结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "mb_kmeans = MiniBatchKMeans(n_clusters = Best_K)\n",
    "\n",
    "y_pred = mb_kmeans.fit_predict(X_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 5,  6,  0, ...,  5, 11,  0])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#保存聚类结果\n",
    "feat_names_Kmeans = \"Kmeans_\" + str(Best_K)\n",
    "train = pd.read_csv(\"training.csv\",header=None,names=['idx','desc'])\n",
    "\n",
    "train_kmeans = pd.concat([train,pd.Series(name = feat_names_Kmeans,data = y_pred)], axis = 1)\n",
    "train_kmeans.to_csv('Company Classification_train_KMeans.csv',index=False,header=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  最后将聚类的结果加到初始文档的后面，如果做的还好一点，可以把每行最大的几个tfidf的值也输出来，这样在分析同类的时候会比较直观"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
